class InterceptorManager<T> {
	handlers: Array<any> = []

	use(onFulfilled: (value: T) => T, onRejected?: (value: T) => T): number {
		this.handlers.push({ onFulfilled, onRejected })
		return this.handlers.length - 1
	}

	eject(id: number): void {
		if (this.handlers[id]) {
			// this.handlers[id] = null
			this.handlers.splice(id, 1)
		}
	}
}
class Axios {
	// 请求全局默认配置
	defaultOptions: DefaultOptions = {
		baseURL: '',
		method: 'GET',
		timeout: 60000,
		header: {},
		dataType: 'json',
		responseType: 'text',
		sslVerify: true,
		withCredentials: false,
		firstIpv4: false
	}

	// 拦截器
	interceptors = {
		request: new InterceptorManager<RequestOptions>(),
		response: new InterceptorManager<RequestSuccessResult>()
	}

	/**
	 *
	 * @param set
	 * @description 如果局部与全局有同名属性，则后面的属性会覆盖前面的属性，相当于Object.assign(全局，局部)
	 */
	setConfig(set: (config: DefaultOptions) => DefaultOptions) {
		this.defaultOptions = set(this.defaultOptions)
	}

	uniRequest<T>(config: RequestOptions): Promise<RequestSuccessResult<T>> {
		let mergedConfig = Object.assign({}, config)

		//  请求拦截器--在发送请求之前做些什么
		this.interceptors.request.handlers.forEach(handler => {
			mergedConfig = handler.onFulfilled(mergedConfig)
		})

		return new Promise((resolve, reject) => {
			uni.request({
				url: this.defaultOptions.baseURL + mergedConfig.url,
				method: mergedConfig.method || this.defaultOptions.method,
				data: mergedConfig.data || {},
				header: Object.assign({}, this.defaultOptions.header, mergedConfig.header),
				dataType: mergedConfig.dataType || this.defaultOptions.dataType,
				responseType: mergedConfig.responseType || this.defaultOptions.responseType, // 支付宝小程序不支持
				timeout: mergedConfig.timeout || this.defaultOptions.timeout,
				sslVerify: mergedConfig.sslVerify || this.defaultOptions.sslVerify, // 验证 ssl 证书 - 仅App安卓端支持（HBuilderX 2.3.3+），不支持离线打包
				withCredentials: mergedConfig.withCredentials || this.defaultOptions.withCredentials, // 跨域请求时是否携带凭证（cookies）- 仅H5支持（HBuilderX 2.6.15+）
				firstIpv4: mergedConfig.firstIpv4 || this.defaultOptions.firstIpv4, // DNS解析时优先使用ipv4 - 仅 App-Android 支持 (HBuilderX 2.8.0+)
				// enableHttp2: mergedConfig.enableHttp2 || false, // 开启 http2 - 微信小程序
				// enableQuic: mergedConfig.enableQuic || false, // 开启 quic - 微信小程序、字节跳动小程序 2.31.0+
				// enableCache: mergedConfig.enableCache || false, // 开启 cache - 微信小程序、字节跳动小程序 2.31.0+
				// enableHttpDNS: mergedConfig.enableHttpDNS|| false, // 是否开启 HttpDNS 服务。如开启，需要同时填入 httpDNSServiceId 。 HttpDNS 用法详见 移动解析HttpDNS - 微信小程序
				// httpDNSServiceId: mergedConfig.httpDNSServiceId|| false, // HttpDNS 服务商 Id。 HttpDNS 用法详见 移动解析HttpDNS - 微信小程序
				// enableChunked: mergedConfig.enableChunked|| false, // HttpDNS 开启 transfer-encoding chunked - 微信小程序
				// forceCellularNetwork: mergedConfig.forceCellularNetwork|| false, // wifi下使用移动网络发送请求 - 微信小程序
				// enableCookie: mergedConfig.enableCookie || false, // 开启后可在headers中编辑cookie - 支付宝小程序 10.2.33+
				// cloudCache: mergedConfig.cloudCache || false, // wifi下使用移动网络发送请求 - 百度小程序 3.310.11+
				// defer: mergedConfig.defer || false, // 控制当前请求是否延时至首屏内容渲染后发送 - 百度小程序 3.310.11+

				success: response => {
					// 响应拦截器--对响应数据做点什么
					if (response.statusCode == 200) {
						this.interceptors.response.handlers.forEach(handler => {
							response = handler.onFulfilled(response)
						})
						resolve(response as RequestSuccessResult<T>)
					} else {
						//  对响应错误做点什么
						this.interceptors.response.handlers.forEach(handler => {
							response = handler.onRejected(response)
							reject(response as RequestSuccessResult)
						})
					}
				},
				fail: error => {
					reject(error)
				}
			})
		})
	}

	/**
	 * @description method GET
	 */
	get<T>(url: string, data?: any, config?: RequestOptions) {
		return this.uniRequest<T>(Object.assign({}, config, { url, method: 'GET', data }))
	}
	/**
	 *
	 * @param url
	 * @param data
	 * @param config
	 * @returns
	 */
	post<T>(url: string, data?: any, config?: RequestOptions) {
		return this.uniRequest<T>(Object.assign({}, config, { url, method: 'POST', data }))
	}
	/**
	 *
	 * @param url
	 * @param data
	 * @param config
	 * @returns
	 */
	put<T>(url: string, data?: any, config?: RequestOptions) {
		return this.uniRequest<T>(Object.assign({}, config, { url, method: 'PUT', data }))
	}
	/**
	 *
	 * @param url
	 * @param data
	 * @param config
	 * @returns
	 */
	delete<T>(url: string, data?: any, config?: RequestOptions) {
		return this.uniRequest<T>(Object.assign({}, config, { url, method: 'DELETE', data }))
	}
	/**
	 *
	 * @param config
	 * @returns
	 */
	request<T>(config?: RequestOptions) {
		return this.uniRequest<T>(Object.assign({}, config))
	}
	/**
	 *
	 * @param url
	 * @param config 具体参数说明： 文档: [http://uniapp.dcloud.io/api/request/network-file?id=downloadfile](http://uniapp.dcloud.io/api/request/network-file?id=downloadfile)
	 */
	upload(url: string, options: UniNamespace.UploadFileOption) {
		return new Promise((resolve, reject) => {
			uni.uploadFile({
				...options,
				url,
				success: res => {
					resolve(res)
				},
				fail: res => {
					reject(res)
				}
			})
		})
	}

	// download() {}
}

export default Axios
